/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.faare.service.services.views.orgchart;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

import org.apache.log4j.Logger;
import org.jpedal.PdfDecoder;
import org.jpedal.fonts.FontMappings;

import quantize.ImageFrame;
import quantize.Quantize;
import quantize.TestQuantize;
import Acme.JPM.Encoders.GifEncoder;

import com.lowagie.text.pdf.PdfException;


/**
 *  This class allows the orgchart generation.
 *
 * This class uses Swing.
 * Application should use PJA (both on Windows and UNIX).
 *
 */
public class OrgChartPanel extends JPanel
{
    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(OrgChartPanel.class);

    // LINE TYPES

    /** Kind of line. */
    public static final short HORIZONTAL_LEFT = 0;

    /** Kind of line. */
    public static final short HORIZONTAL_CENTER = 1;

    /** Kind of line. */
    public static final short HORIZONTAL_RIGHT = 2;

    /** Kind of orgchart, and kind of line. */
    public static final short VERTICAL = 3;

    /** Kind of orgchart, and kind of line. */
    public static final short HORIZONTAL = 4;

    /** Kind of orgchart. */
    public static final short TREE = 5;

    /** Orgchart mode. */
    public static final short COMPRESSED = 6;

    /** Orgchart mode (deprecated). */
    public static final short LARGE = 7;

    /** Kind of orgchart. */
    public static final short SEMALIKE = 8;

    /** Kind of line. */
    public static final short NONE = -1;

    // node properties

    /** Name of node. */
    public static final String NAME = "name";

    /** Dname of node. */
    public static final String DN = "dn";

    /** Photo of person in node. */
    public static final String PHOTO = "photo";

    /** Node level in hashtable. */
    public static final String LEVEL = "level";

    /** Cell width in hashtable. */
    public static final String WIDTH = "dispwidth";

    /** Cell height in hashtable. */
    public static final String HEIGHT = "dispheight";

    /** X coordinate of cell in hashtable. */
    public static final String XCOORD = "dispx";

    /** Y coordinate of cell in hashtable. */
    public static final String YCOORD = "dispy";

    /** Cell font size in hashtable. */
    public static final String FONTSIZE = "fontsize";

    /** Node attributes in hashtable. */
    public static final String ATTRIBS = "attribs";

    /** Computed X coordinate un hashtable. */
    public static final String X = "computedx";

    /** Global attribute list. */
    private static List attribs;

    /** Root cell. */
    private static XJButton baseCell = null;

    /** Orgchart kind. */
    private static int direction = HORIZONTAL;

    /** Orgchart mode. */
    private static int mode = COMPRESSED;

    /** Number of characters in longest label. */
    private static int nbcar = 0;

    /** Longest label size. */
    private static int longest = 0;

    /** Horizontal space. */
    public static final int SPACEH = 50;

    /** Vertical space. */
    public static final int SPACEV = 10;

    /** Some space. */
    public static final int SSPACE = 30;

    /** Maximum width. */
    private static int maxX = 0;

    /** Maximum height. */
    private static int maxY = 0;

    /** Current instance. */
    private static OrgChartPanel orgchart = null;

    /** Attributes per level. */
    private static Hashtable levelAttribs;

    /** Orgchart criteria. */
    private static Object[] crits;

    // colors and fonts

    /** Background color. */
    private Color backGround;

    /** Text color. */
    private Color textColor;

    /** Text font. */
    private Font textFont;

    /** Text font. */
    private Font titleFont;

    /** Cell color. */
    private Color cellColor;

    /** List of panels with lines. */
    private ArrayList horizList = null;

    /** The head of the orgchart. */
    private DefaultMutableTreeNode root;

    /** Maximum width of a cell. */
    private int maxWidth = 500;

    /** Maximum height of a cell. */
    private int maxHeight = 0;

    /** Number of columns in Sema mode. */
    private int nbCols = 2;

//DW/2615/BeginPatch
    /** Default photo file name. */
    private String defaultPhoto = null;
//DW/2615/EndPatch

    /** Space left for photo + margin. */
    public static final int DX_PHOTO = 55;

    /** Space left for margin (no photo). */
    public static final int DX = 5;

    /** Photo size. */
    public static final int PHOTO_SZ = 50;

    /** Minimum width. */
    private static final int MINW = 70;

    /** Width factor. */
    private static final int W_FACTOR = 8;

    /** Maximum size supported by PDF lib. */
    private static final int MAX_PDF = 14400;

    /** Maximum nb of colors supported by GIF. */
    private static final int MAX_GIF = 256;

    /**
     * Creates a new OrgChartPanel object.
     *
     * @param aroot  Root node.
     * @param level  Depth level. (deprecated)
     */
    public OrgChartPanel(final DefaultMutableTreeNode aroot, final int level)
    {
        this(aroot, level, true);
        _logger.debug("OrgChartPanel constructor1 level: " + level);
    }

    /**
     * Creates a new OrgChartPanel object.
     *
     * @param aroot  Root node
     * @param level  Depth level. (deprecated)
     * @param start  If true, generates orgchart immediately.
     */
    public OrgChartPanel(final DefaultMutableTreeNode aroot, final int level,
        final boolean start)
    {
        super();
        _logger.debug("OrgChartPanel constructor2 level: " + level);
        _logger.debug("OrgChartPanel constructor2 start: " + start);

        orgchart = this;
        backGround = Color.white;
        textColor = Color.black;

        Font f;
        f = getFont();
        textFont = new Font(f.getName(), Font.BOLD, f.getSize());
        titleFont = f;
        setBackground(backGround);
        cellColor = Color.lightGray;

        attribs = new ArrayList();
        attribs.add("photo");
        attribs.add("displayname");
        attribs.add("title");

        setRootNode(aroot);

        if (start)
        {
            doIt();
        }

        crits = null;
        nbcar = 0;
        longest = 0;
        doCompute(this);
    }

    /**
     * Creates a new OrgChartPanel object.
     *
     * @param aroot  Root node.
     * @param level  Depth level. (deprecated)
     * @param acrits  Criteria.
     * @param listatt  Attributes per level.
     */
    public OrgChartPanel(final DefaultMutableTreeNode aroot, final int level,
        final Object[] acrits, final Hashtable listatt)
    {
        this(aroot, level, false);
        crits = acrits;
        levelAttribs = listatt;
        _logger.debug("OrgChartPanel constructor3 level: " + level);
    }

    /**
     * Gets orgchart kind.
     *
     * @return The orgchart kind.
     */
    public static int getDirection()
    {
        return direction;
    }

    /**
     * Sets orgchart mode.
     *
     * @param amode  Orgchart mode.
     */
    public void setMode(final int amode)
    {
        OrgChartPanel.mode = amode;
    }

    /**
     * Gets orgchart mode.
     *
     * @return The orgchart mode.
     */
    public static int getMode()
    {
        return mode;
    }

    /**
     * Sets orgchart kind.
     *
     * @param dir  Orgchart kind.
     */
    public void setDirection(final int dir)
    {
        _logger.debug("setDirection1 dir = " + dir);
        direction = dir;
        _logger.debug("setDirection2 direction = " + direction);
    }

    /**
     * Sets root node.
     *
     * @param aRoot  Root node.
     */
    public final void setRootNode(final DefaultMutableTreeNode aRoot)
    {
        root = aRoot;
    }

    /**
     * Gets the root node.
     *
     * @return The root node.
     */
    public final DefaultMutableTreeNode getRoot()
    {
        return root;
    }

    /**
     * Adds an attribute to a cell.
     *
     * @param pan  Enclosing panel.
     * @param gl   Gridbag layout.
     * @param gc   Gridbag constraints.
     * @param lab  Label to add.
     */
    private void addAttrib(final JPanel pan, final GridBagLayout gl,
        final GridBagConstraints gc, final JLabel lab)
    {
        _logger.debug("addAttrib");
        gl.setConstraints(lab, gc);
        pan.add(lab);
        gc.gridy++;
    }

    /**
     * Sets font size of a label according to cell content.
     *
     * @param label  Label to set.
     * @param base   Base font.
     * @param maxw   Max width.
     * @param info   Node hashtable.
     * @param isphoto  Photo presence flag.
     */
    private void setFont(final JLabel label, final Font base, final int maxw,
        final Hashtable info, final boolean isphoto)
    {
        _logger.debug("setFont");

        int maxw4t = maxw - DX_PHOTO;

        if (!isphoto)
        {
            maxw4t = maxw - DX;
        }

        String text = label.getText();
        Font curFont = new Font(base.getName(), base.getStyle(), base.getSize());
        Font nextFont;
        int txtsize = 0;

        do
        {
            txtsize = (int) getFontMetrics(curFont)
                                .getStringBounds(text, getGraphics()).getWidth();
            label.setFont(curFont);
            nextFont = new Font(curFont.getName(), curFont.getStyle(),
                    curFont.getSize() - 1);
            curFont = nextFont;
        }
        while ((txtsize > maxw4t) && (curFont.getSize() > 1));

        if (info.get(FONTSIZE) != null)
        {
            int oldsize = ((Integer) info.get(FONTSIZE)).intValue();

            if (oldsize > curFont.getSize())
            {
                info.put(FONTSIZE, new Integer(curFont.getSize()));
            }
        }
        else
        {
            info.put(FONTSIZE, new Integer(curFont.getSize()));
        }
    }

    /**
     * Creates the contents of a cell containing the info related to the node.
     *
     * @param node  Subject node.
     *
     * @return The generated panel.
     */
    private JPanel createNameAndPhotoLabel(final DefaultMutableTreeNode node)
    {
        _logger.debug("createNameAndPhotoLabel");

        Hashtable info = (Hashtable) node.getUserObject();
        boolean isPhoto = (info.get(PHOTO) != null);

        JPanel res = new JPanel(new BorderLayout(0, 0));
        res.setOpaque(false);

        JPanel centerPanel = new JPanel();

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.CENTER;
        c.fill = GridBagConstraints.BOTH;
        c.gridy = 0;
        c.gridy = 0;
        c.gridx = 0;
        c.weighty = 0.0;
        c.weightx = 1.0;

        GridBagLayout gridbag = new GridBagLayout();
        centerPanel.setLayout(gridbag);

        Integer alevel = (Integer) info.get(LEVEL);

        if ((crits != null) && (levelAttribs != null) &&
                (alevel.intValue() > crits.length))
        {
            alevel = new Integer(levelAttribs.size() - 1);
        }

        List alist = null;

        if (levelAttribs != null)
        {
            alist = (List) levelAttribs.get(alevel);
        }

        _logger.debug("name " + info.get(NAME) + " level " + alevel);

        Iterator iter;

        if (alist != null)
        {
            iter = alist.iterator();
        }
        else
        {
            iter = attribs.iterator();
        }

        while (iter.hasNext())
        {
            String attyp = (String) iter.next();

            if (!attyp.equals(PHOTO))
            {
                String atVal = null;

                if (attyp.equals("displayname"))
                {
                    atVal = (String) info.get(NAME);
                }
                else
                {
                    atVal = (String) info.get(attyp);
                }

                if (atVal != null)
                {
                    JLabel label = new JLabel(atVal);
                    label.setBackground(Color.blue);
                    setFont(label, titleFont, getMaxWidth(), info, isPhoto);

                    label.setForeground(textColor);
                    label.setHorizontalAlignment(SwingConstants.CENTER);

                    addAttrib(centerPanel, gridbag, c, label);
                }
            }
        }

        centerPanel.setOpaque(false);

        // PHOTO
        try
        {
            byte[] photo = (byte[]) info.get(PHOTO);

//DW/2615/BeginPatch
            ImageIcon image = null;
            if (photo != null)
            {
                //ImageIcon image = new ImageIcon(photo);
                image = new ImageIcon(photo);
            }
            else if (defaultPhoto != null)
            {
                image = new ImageIcon(defaultPhoto);
            }

            if (image != null)
            {
//DW/2615/EndPatch
                Image im = image.getImage();
                Image newIm = im.getScaledInstance(-1, PHOTO_SZ, Image.SCALE_FAST);
                image = new ImageIcon(newIm);

                if (image != null)
                {
                    JLabel photoLab = new JLabel(image);
                    photoLab.setBorder(new EmptyBorder(0, 0, 0, 2));
                    res.add(photoLab, BorderLayout.WEST);
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }

        res.add(centerPanel, BorderLayout.CENTER);

        return res;
    }

    /**
     * Creates a cell related to a node.
     *
     * @param node  Subject node.
     *
     * @return The created panel.
     */
    private JPanel createPP(final DefaultMutableTreeNode node)
    {
        _logger.debug("createPP");

        int state = 0;
        Hashtable info = (Hashtable) node.getUserObject();

        XJButton p1 = new XJButton(node, this);

        if (isRoot(node))
        {
            baseCell = p1;
        }

        p1.setLayout(new BorderLayout());

        Color aColor = cellColor;

        JPanel gars1 = createNameAndPhotoLabel(node);
        p1.add(gars1);
        p1.setBackground(aColor);
        p1.setMargin(new Insets(0, 0, 0, 0));

        JPanel pp1 = new JPanel();
        pp1.setLayout(new BorderLayout());
        pp1.add(p1, BorderLayout.CENTER);

        int w = getMaxWidth();
        Integer hlevel = (Integer) info.get(LEVEL);

        if ((crits != null) && (levelAttribs != null) &&
                (hlevel.intValue() > crits.length))
        {
            hlevel = new Integer(levelAttribs.size() - 1);
        }

        int h = getMaxHeight(hlevel);
        p1.setMinimumSize(new Dimension(w, h));
        p1.setPreferredSize(new Dimension(w, h));
        pp1.setMaximumSize(new Dimension(w, h));

        return pp1;
    }

    /**
     * Creates a panel surrounding a cell and its children (horizontal
     *  or vertical kinds of orgchart, large mode).
     *
     * @param node      The top cell of the panel.
     * @param hasChild  Children presence flag.
     * @param type      Kind of required OrgLine.
     * @param horiza    Should be the panel containing the cell and brothers
     *                  for the first child, else null.
     * @param horizb    should be the panel containing the cell and brothers
     *                  for the last child, else null.
     *
     * @return Created panel.
     */
    private JPanel createVert(final DefaultMutableTreeNode node,
        final boolean hasChild, final short type, final XJPanel horiza,
        final XJPanel horizb)
    {
        _logger.debug("createVert");

        JPanel vert11 = new JPanel();

        if (getDirection() == HORIZONTAL)
        {
            vert11.setLayout(new BoxLayout(vert11, BoxLayout.Y_AXIS));
        }
        else
        {
            vert11.setLayout(new BoxLayout(vert11, BoxLayout.X_AXIS));
        }

        JPanel pp11 = createPP(node);

        if (type != NONE)
        {
            if (getDirection() == HORIZONTAL)
            {
                pp11.add(new OrgLine(type, backGround), BorderLayout.NORTH);
            }
            else
            {
                vert11.add(new OrgLine(type, backGround));
            }
        }

        vert11.add(pp11);

        if (hasChild)
        {
            if (getNbChildExpanded(node) > 1)
            {
                vert11.add(new OrgLine(HORIZONTAL_LEFT, backGround));
            }
            else
            {
                vert11.add(new OrgLine(backGround));
            }
        }
        else
        {
            if (getDirection() == HORIZONTAL)
            {
                vert11.add(Box.createVerticalGlue());
            }
            else
            {
                vert11.add(Box.createHorizontalGlue());
            }
        }

        if (horiza != null)
        {
            horiza.setP1(pp11);
        }

        if (horizb != null)
        {
            horizb.setP2(pp11);
        }

        vert11.setBackground(backGround);

        return vert11;
    }

    /**
     * Recomputes the position of all lines in the horizontal panels.
     */
    private void recalcule()
    {
        _logger.debug("recalcule");

        for (int i = 0; i < horizList.size(); i++)
        {
            XJPanel horiz = (XJPanel) (horizList.get(i));
            horiz.recalcule();
        }
    }

    /**
     * Gets number of children of a node.
     *
     * @param node  Node.
     *
     * @return Number of children.
     */
    public final int getNbChildExpanded(final DefaultMutableTreeNode node)
    {
        return node.getChildCount();
    }

    /**
     * Tests whether node is root node.
     *
     * @param node  Node.
     *
     * @return True if the node is the root node, else false.
     */
    public final boolean isRoot(final DefaultMutableTreeNode node)
    {
        _logger.debug("isRoot");

        return (node == getRoot());
    }

    /**
     * Creates a panel containing all children of a cell (horizontal
     *  or vertical kinds of orgchart, large mode).
     *
     * @param node Father node.
     *
     * @return The created panel.
     */
    private JPanel processChildren(final DefaultMutableTreeNode node)
    {
        _logger.debug("processChildren");

        int nbChildren = getNbChildExpanded(node);

        if (nbChildren == 1)
        {
            JPanel horizc = new JPanel();

            if (getDirection() == HORIZONTAL)
            {
                horizc.setLayout(new BoxLayout(horizc, BoxLayout.X_AXIS));
            }
            else
            {
                horizc.setLayout(new BoxLayout(horizc, BoxLayout.Y_AXIS));
            }

            DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(0);
            boolean hasChild = (getNbChildExpanded(child) == 0) ? false : true;
            JPanel vertc = createVert(child, hasChild, NONE, null, null);

            if (hasChild)
            {
                JPanel pchild = processChildren(child);
                vertc.add(pchild);
            }

            horizc.add(vertc);
            horizc.setBackground(backGround);

            return horizc;
        }
        else
        {
            // assume != 0
            XJPanel horizc = new XJPanel();

            if (getDirection() == HORIZONTAL)
            {
                horizc.setLayout(new BoxLayout(horizc, BoxLayout.X_AXIS));
            }
            else
            {
                horizc.setLayout(new BoxLayout(horizc, BoxLayout.Y_AXIS));
            }

            DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(0);
            boolean hasChild = (getNbChildExpanded(child) == 0) ? false : true;
            JPanel vertc1 = createVert(child, hasChild, HORIZONTAL_LEFT, horizc, null);
            horizc.setV1(vertc1);

            if (hasChild)
            {
                JPanel pchild = processChildren(child);
                vertc1.add(pchild);
            }

            horizc.add(vertc1);

            if (getDirection() == HORIZONTAL)
            {
                horizc.add(Box.createHorizontalStrut(SPACEV));
            }
            else
            {
                horizc.add(Box.createVerticalStrut(SPACEV));
            }

            horizc.setBackground(backGround);

            for (int i = 1; i < (nbChildren - 1); i++)
            {
                DefaultMutableTreeNode childi = (DefaultMutableTreeNode) node.getChildAt(i);
                hasChild = (getNbChildExpanded(childi) == 0) ? false : true;

                JPanel vertci = createVert(childi, hasChild, HORIZONTAL_CENTER,
                        null, null);

                if (hasChild)
                {
                    JPanel pchild = processChildren(childi);
                    vertci.add(pchild);
                }

                horizc.add(vertci);

                if (getDirection() == HORIZONTAL)
                {
                    horizc.add(Box.createHorizontalStrut(SPACEV));
                }
                else
                {
                    horizc.add(Box.createVerticalStrut(SPACEV));
                }
            }

            DefaultMutableTreeNode childn = (DefaultMutableTreeNode) node.getChildAt(nbChildren -
                    1);
            hasChild = (getNbChildExpanded(childn) == 0) ? false : true;

            JPanel vertcn = createVert(childn, hasChild, HORIZONTAL_RIGHT,
                    null, horizc);
            horizc.setV2(vertcn);

            if (hasChild)
            {
                JPanel pchild = processChildren(childn);
                vertcn.add(pchild);
            }

            horizc.add(vertcn);

            horizList.add(horizc);

            return horizc;
        }
    }

    /**
     * Computes max width of orgchart cells.
     *
     * @param node Root node.
     */
    public final void computeMaxWidth(final DefaultMutableTreeNode node)
    {
        _logger.debug("computeMaxWidth");

        Enumeration enum1 = node.children();

        // DW/2549 : case there is no child node
        if (!enum1.hasMoreElements()) // only one node
        {
            Hashtable info = (Hashtable) node.getUserObject();
            computeMaxWidthElt(info);
        }

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
            Hashtable info = (Hashtable) childnode.getUserObject();

            computeMaxWidthElt(info);

            computeMaxWidth(childnode);
        }

        setMaxWidth(MINW + longest);
    }

    /**
     * Computes max width of one cell.
     *
     * @param info  Node hashtable.
     */
    private void computeMaxWidthElt(final Hashtable info)
    {
        String value2 = (String) info.get(NAME);

        if (value2.length() > nbcar)
        {
            nbcar = value2.length();
            longest = (int) getFontMetrics(textFont)
                                .getStringBounds(value2, getGraphics())
                                .getWidth();
        }

        Iterator iter = attribs.iterator();

        while (iter.hasNext())
        {
            String attyp = (String) iter.next();

            if (!attyp.equals(PHOTO))
            {
                String atVal = (String) info.get(attyp);

                if ((atVal != null) && (atVal.length() > nbcar))
                {
                    nbcar = atVal.length();
                    longest = (int) getFontMetrics(titleFont)
                                        .getStringBounds(atVal, getGraphics())
                                        .getWidth();
                }
            }
        }

        if (levelAttribs != null)
        {
            Enumeration allattrs = levelAttribs.elements();

            while (allattrs.hasMoreElements())
            {
                iter = ((List) allattrs.nextElement()).iterator();

                while (iter.hasNext())
                {
                    String attyp = (String) iter.next();

                    if (!attyp.equals(PHOTO))
                    {
                        String atVal = (String) info.get(attyp);

                        if ((atVal != null) && (atVal.length() > nbcar))
                        {
                            nbcar = atVal.length();
                            longest = (int) getFontMetrics(titleFont)
                                                .getStringBounds(atVal,
                                    getGraphics()).getWidth();
                        }
                    }
                }
            }
        }
    }

    /**
     * Gets maximum width of cells.
     *
     * @return The maximum width.
     */
    private int getMaxWidth()
    {
        return maxWidth;
    }

    /**
     * Sets maximum width of cells.
     *
     * @param w  Maximum width.
     */
    private void setMaxWidth(final int w)
    {
        maxWidth = w;
    }

    /**
     * Gets maximum height of cells for a given level.
     *
     * @param level  Level.
     *
     * @return The maximum height.
     */
    private int getMaxHeight(final Integer level)
    {
        _logger.debug("getMaxHeight");

        List alist = null;

        if (levelAttribs != null)
        {
            alist = (List) levelAttribs.get(level);
        }

        if (alist == null)
        {
            alist = attribs;
        }

        Enumeration enum1 = getRoot().depthFirstEnumeration();
        maxHeight = 0;

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) enum1.nextElement();
            boolean isExp = true;
            DefaultMutableTreeNode curnode = (DefaultMutableTreeNode) node.getParent();

            while ((curnode != null) && !isRoot(curnode))
            {
                curnode = (DefaultMutableTreeNode) curnode.getParent();
            }

            boolean isPhoto = false;
            int fh = 0;

            if (isExp)
            {
                Hashtable info = (Hashtable) node.getUserObject();
                Integer alevel = (Integer) info.get(LEVEL);

                if ((alevel == null) ||
                        (alevel.intValue() == level.intValue()))
                {
                    Iterator iter = alist.iterator();
                    int nbatt = 0;

                    while (iter.hasNext())
                    {
                        String attyp = (String) iter.next();

                        if (!attyp.equals(PHOTO))
                        {
                            String atVal = null;

                            if (attyp.equals("displayname"))
                            {
                                atVal = (String) info.get(NAME);
                            }
                            else
                            {
                                atVal = (String) info.get(attyp);
                            }

                            if (atVal != null)
                            {
                                int ah = (int) getFontMetrics(titleFont)
                                                   .getStringBounds(atVal,
                                        getGraphics()).getHeight() +
                                    getFontMetrics(titleFont).getDescent();
                                fh += ah;
                            }
                        }

                        if (!isPhoto && (info.get(PHOTO) != null))
                        {
                            isPhoto = true;
                        }
                    }

                    if (isPhoto && (fh < PHOTO_SZ))
                    {
                        fh = PHOTO_SZ;
                    }

                    if (fh > maxHeight)
                    {
                        maxHeight = fh;
                    }
                }
            }
        }

        return maxHeight;
    }

    /**
     * Sets default maximum height.
     *
     * @param h  Maximum height.
     */
    private void setMaxHeight(final int h)
    {
        maxHeight = h;
    }

    /**
     * Creates a panel surrounding a cell and its children (tree mode).
     *
     * @param node      The top cell of the panel
     * @param hasChild  Children presence flag
     * @param type      Kind of required OrgLine
     * @param horiza    Should be the panel containing the cell and brothers
     *                   for the first child, else null.
     * @param horizb    Should be the panel containing the cell and brothers
     *                   for the last child, else null.
     *
     * @return The created panel.
     */
    private JPanel treeCreateVert(final DefaultMutableTreeNode node,
        final boolean hasChild, final short type, final XJPanel horiza,
        final XJPanel horizb)
    {
        _logger.debug("treeCreateVert");

        FlowLayout fl = new FlowLayout();
        fl.setVgap(0);
        fl.setHgap(0);
        fl.setAlignment(FlowLayout.LEFT);

        JPanel cur = new JPanel(fl);

        int level = node.getLevel();
        int hlevel = level;
        Hashtable info = (Hashtable) node.getUserObject();

        if ((crits != null) && (levelAttribs != null) &&
                (hlevel > crits.length))
        {
            hlevel = levelAttribs.size();
        }

        level -= getRoot().getLevel();

        JPanel v1 = new JPanel();
        v1.setLayout(new BorderLayout());

        JPanel pp11 = createPP(node);
        v1.add(pp11, BorderLayout.NORTH);

        if (getNbChildExpanded(node) != 0)
        {
            v1.add(new OrgLine1(backGround), BorderLayout.WEST);
        }
        else
        {
            v1.add(Box.createVerticalStrut(SPACEV), BorderLayout.SOUTH);
        }

        if (level > 0)
        {
            int height = getMaxHeight(new Integer(hlevel));
            boolean last = (((DefaultMutableTreeNode) node.getParent()).getLastChild() == node) ?
                true : false;
            JPanel v0 = new JPanel();
            v0.setLayout(new BorderLayout());
            v0.add(new OrgLine1(HORIZONTAL_LEFT, backGround, height, last),
                BorderLayout.NORTH);

            int lh = height;

            if (getNbChildExpanded(node) != 0)
            {
                if (!last)
                {
                    v0.add(new OrgLine1(VERTICAL, backGround, SPACEV),
                        BorderLayout.CENTER);
                }
                else
                {
                    v0.add(Box.createVerticalStrut(SPACEV), BorderLayout.CENTER);
                }

                lh += SPACEV;
            }
            else
            {
                if (!last)
                {
                    v0.add(new OrgLine1(VERTICAL, backGround, SPACEV),
                        BorderLayout.SOUTH);
                }
                else
                {
                    v0.add(Box.createVerticalStrut(SPACEV), BorderLayout.SOUTH);
                }

                lh += SPACEV;
            }

            TreeNode[] parents = node.getPath();

            level += getRoot().getLevel();

            int i0 = 2 + getRoot().getLevel();

            for (int i = i0; i <= level; i++)
            {
                if (((DefaultMutableTreeNode) parents[i - 2]).getLastChild() != parents[i -
                        1])
                {
                    cur.add(new OrgLine1(VERTICAL, backGround, lh));
                }
                else
                {
                    cur.add(Box.createHorizontalStrut(SPACEH));
                }
            }

            v0.setBackground(backGround);
            cur.add(v0);
        }

        cur.add(v1);
        cur.setBackground(backGround);
        cur.setMaximumSize(new Dimension(
                (int) cur.getMaximumSize().getWidth(),
                (int) v1.getPreferredSize().getHeight()));
        v1.setBackground(backGround);

        return cur;
    }

    /**
     * Creates a panel containing all children of a cell (tree mode).
     *
     * @param node Father node
     *
     */
    private void treeProcessChildren(final DefaultMutableTreeNode node)
    {
        _logger.debug("treeProcessChildren");

        int nbChildren = getNbChildExpanded(node);

        for (int i = 0; i < nbChildren; i++)
        {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
            add(treeCreateVert(child, true, NONE, null, null));
            treeProcessChildren(child);
        }
    }

    /**
     * Gets max height in compressed mode.
     *
     * @param info  Node hashtable.
     *
     * @return The max height.
     */
    private int getCompMaxHeight(final Hashtable info)
    {
        _logger.debug("getCompMaxHeight");

        Integer hlevel = (Integer) info.get(LEVEL);

        if ((crits != null) && (levelAttribs != null) &&
                (hlevel.intValue() > crits.length))
        {
            hlevel = new Integer(levelAttribs.size());
        }

        return getMaxHeight(hlevel);
    }

    /**
     * Gets next node with same level, as the name says it !
     *
     * @param node  Node
     *
     * @return The next node.
     */
    private DefaultMutableTreeNode getNextNodeWithSameLevel(
        final DefaultMutableTreeNode node)
    {
        _logger.debug("getNextNodeWithSameLevel");

        DefaultMutableTreeNode ret = node.getNextNode();

        while ((ret != null) && (node.getLevel() != ret.getLevel()))
        {
            ret = ret.getNextNode();
        }

        return ret;
    }

    /**
     * Computes cells coordinates in compressed mode.
     */
    private void doComputeCondenseCoords()
    {
        _logger.debug("doComputeCondenseCoords");

        DefaultMutableTreeNode cur;
        Hashtable info;
        int curx = 0;
        int maxLevel = getRoot().getDepth();

        cur = getRoot();
        info = (Hashtable) cur.getUserObject();
        info.put(X, new Float(curx));

        int l0 = cur.getLevel();
        maxLevel += l0;

        // init
        for (int l = l0 + 1; l <= maxLevel; l++)
        {
            curx = 0;

            Enumeration enum1 = getRoot().depthFirstEnumeration();

            while (enum1.hasMoreElements())
            {
                cur = (DefaultMutableTreeNode) enum1.nextElement();

                if (cur.getLevel() == l)
                {
                    info = (Hashtable) cur.getUserObject();
                    info.put(X, new Float(curx));

                    if (direction == HORIZONTAL)
                    {
                        curx += (float) (getMaxWidth() + SPACEV);
                    }
                    else
                    {
                        curx += (float) (getCompMaxHeight(info) + SPACEV);
                    }
                }
            }
        }

        // computing
        for (int l = maxLevel - 1; l >= l0; l--)
        {
            Enumeration enum1 = getRoot().depthFirstEnumeration();

            while (enum1.hasMoreElements())
            {
                cur = (DefaultMutableTreeNode) enum1.nextElement();

                if ((cur.getLevel() == l) && (getNbChildExpanded(cur) > 0))
                {
                    DefaultMutableTreeNode fc = (DefaultMutableTreeNode) cur.getFirstChild();

                    if (getNbChildExpanded(fc) == 0)
                    {
                        DefaultMutableTreeNode achild = fc.getNextSibling();
                        boolean found = false;

                        while (!found && (achild != null))
                        {
                            found = (getNbChildExpanded(achild) > 0);

                            if (!found)
                            {
                                achild = achild.getNextSibling();
                            }
                        }

                        if (found)
                        {
                            int cidx = cur.getIndex(achild);
                            Hashtable ichild = (Hashtable) achild.getUserObject();
                            float xchild = ((Float) ichild.get(X)).floatValue();

                            for (int ci = 0; ci < cidx; ci++)
                            {
                                DefaultMutableTreeNode childi = (DefaultMutableTreeNode) cur.getChildAt(ci);
                                Hashtable ii = (Hashtable) childi.getUserObject();
                                float dx;

                                if (direction == HORIZONTAL)
                                {
                                    dx = (getMaxWidth() + SPACEV);
                                }
                                else
                                {
                                    dx = (getCompMaxHeight(ii) + SPACEV);
                                }

                                ii.put(X, new Float(xchild -
                                        ((cidx - ci) * dx)));
                            }
                        }
                        else
                        {
                            achild = getNextNodeWithSameLevel((DefaultMutableTreeNode) cur.getLastChild());

                            if (achild != null)
                            {
                                Hashtable ichild = (Hashtable) achild.getUserObject();
                                float xchild = ((Float) ichild.get(X)).floatValue();
                                int cn = cur.getChildCount();

                                for (int ci = 0; ci < cn; ci++)
                                {
                                    DefaultMutableTreeNode childi = (DefaultMutableTreeNode) cur.getChildAt(ci);
                                    Hashtable ii = (Hashtable) childi.getUserObject();
                                    float dx;

                                    if (direction == HORIZONTAL)
                                    {
                                        dx = (getMaxWidth() + SPACEV);
                                    }
                                    else
                                    {
                                        dx = (getCompMaxHeight(ii) +
                                            SPACEV);
                                    }

                                    ii.put(X,
                                        new Float(xchild - ((cn - ci) * dx)));
                                }
                            }
                        }
                    }
                }
            }

            enum1 = getRoot().depthFirstEnumeration();

            while (enum1.hasMoreElements())
            {
                cur = (DefaultMutableTreeNode) enum1.nextElement();

                if (cur.getLevel() == l)
                {
                    if (getNbChildExpanded(cur) > 0)
                    {
                        DefaultMutableTreeNode fc = (DefaultMutableTreeNode) cur.getFirstChild();
                        DefaultMutableTreeNode lc = (DefaultMutableTreeNode) cur.getLastChild();
                        Hashtable fi = (Hashtable) fc.getUserObject();
                        Hashtable li = (Hashtable) lc.getUserObject();
                        Hashtable ci = (Hashtable) cur.getUserObject();
                        float fx = ((Float) fi.get(X)).floatValue();
                        float lx = ((Float) li.get(X)).floatValue();
                        float cx = ((Float) ci.get(X)).floatValue();
                        float delta = ((fx + lx) / 2) - cx;

                        if (direction == VERTICAL)
                        {
                            delta += (((float) (getCompMaxHeight(fi) -
                            getCompMaxHeight(ci))) / (float) 2);
                        }

                        if (delta <= 0)
                        {
                            delta = -delta;

                            int nbc = cur.getChildCount();
                            boolean isChildLevel2 = false;

                            for (int childi = 0;
                                    (childi < nbc) && !isChildLevel2;
                                    childi++)
                            {
                                isChildLevel2 = getNbChildExpanded((DefaultMutableTreeNode) cur.getChildAt(
                                            childi)) > 0;
                            }

                            boolean collision = false;

                            if (isChildLevel2)
                            {
                                collision = true;
                            }
                            else
                            {
                                DefaultMutableTreeNode next = getNextNodeWithSameLevel(lc);

                                if (next != null)
                                {
                                    Hashtable nexti = (Hashtable) next.getUserObject();
                                    float nextx = ((Float) nexti.get(X)).floatValue();
                                    float dx;

                                    if (direction == HORIZONTAL)
                                    {
                                        dx = (getMaxWidth() + SPACEV);
                                    }
                                    else
                                    {
                                        dx = (getCompMaxHeight(li) +
                                            SPACEV);
                                    }

                                    if ((lx + delta + dx) > nextx)
                                    {
                                        collision = true;
                                    }
                                }
                            }

                            Enumeration enum2 = getRoot().depthFirstEnumeration();

                            while (enum2.hasMoreElements() && collision)
                            {
                                DefaultMutableTreeNode cur1 = (DefaultMutableTreeNode) enum2.nextElement();

                                //!!
                                if ((cur1.getLevel() > (l + 1)))
                                {
                                    DefaultMutableTreeNode cur2 = (DefaultMutableTreeNode) (cur1.getPath()[l +
                                        1]);
                                    Hashtable i1 = (Hashtable) cur1.getUserObject();
                                    Hashtable i2 = (Hashtable) cur2.getUserObject();
                                    float x1 = ((Float) i1.get(X)).floatValue();
                                    float x2 = ((Float) i2.get(X)).floatValue();

                                    if (x2 >= fx)
                                    {
                                        i1.put(X, new Float(x1 + delta));
                                    }
                                }
                            }

                            enum2 = getRoot().depthFirstEnumeration();

                            while (enum2.hasMoreElements())
                            {
                                DefaultMutableTreeNode cur1 = (DefaultMutableTreeNode) enum2.nextElement();

                                if ((cur1.getLevel() == (l + 1)) &&
                                        (collision || cur.isNodeChild(cur1)))
                                {
                                    Hashtable i1 = (Hashtable) cur1.getUserObject();
                                    float x1 = ((Float) i1.get(X)).floatValue();

                                    if (x1 >= fx)
                                    {
                                        i1.put(X, new Float(x1 + delta));
                                    }
                                }
                            }
                        }
                        else
                        {
                            Enumeration enum3 = getRoot().depthFirstEnumeration();

                            while (enum3.hasMoreElements())
                            {
                                DefaultMutableTreeNode cur1 = (DefaultMutableTreeNode) enum3.nextElement();

                                if (cur1.getLevel() == l)
                                {
                                    Hashtable i1 = (Hashtable) cur1.getUserObject();
                                    float x1 = ((Float) i1.get(X)).floatValue();

                                    if (x1 >= cx)
                                    {
                                        i1.put(X, new Float(x1 + delta));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Generates orgchart in compressed mode.
     */
    private void doDessineCondense()
    {
        _logger.debug("doDessineCondense");

        int maxLevel = getRoot().getDepth();
        int l0 = getRoot().getLevel();
        maxLevel += l0;

        if (direction == HORIZONTAL)
        {
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        }
        else
        {
            setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
        }

        for (int l = l0; l <= maxLevel; l++)
        {
            JPanel panel = new JPanel();

            if (direction == HORIZONTAL)
            {
                panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
            }
            else
            {
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
            }

            Enumeration enum4 = getRoot().depthFirstEnumeration();
            boolean first = true;
            float x = 0;
            float prevx = 0;

            while (enum4.hasMoreElements())
            {
                DefaultMutableTreeNode cur = (DefaultMutableTreeNode) enum4.nextElement();

                if (cur.getLevel() == l)
                {
                    Hashtable info = (Hashtable) cur.getUserObject();
                    int delta;

                    if (direction == HORIZONTAL)
                    {
                        delta = getMaxWidth() + SPACEV;
                    }
                    else
                    {
                        delta = getCompMaxHeight(info) + SPACEV;
                    }

                    x = ((Float) info.get(X)).floatValue();

                    if (first)
                    {
                        if (x > 0)
                        {
                            if (direction == HORIZONTAL)
                            {
                                panel.add(Box.createHorizontalStrut((int) x));
                            }
                            else
                            {
                                panel.add(Box.createVerticalStrut((int) x));
                            }
                        }
                    }
                    else if ((x - prevx) > delta)
                    {
                        int size = (int) (x - prevx - delta);

                        if (cur.getParent().getChildAt(0) == cur)
                        {
                            if (direction == HORIZONTAL)
                            {
                                panel.add(Box.createHorizontalStrut(size));
                            }
                            else
                            {
                                panel.add(Box.createVerticalStrut(size));
                            }
                        }
                        else
                        {
                            XJPanel1 xjp1 = new XJPanel1(size);
                            xjp1.setBackground(backGround);
                            panel.add(xjp1);
                        }
                    }

                    JPanel cpanel = new XJPanel2(cur);
                    cpanel.setLayout(new BorderLayout());

                    int w = 0;
                    int h = 0;

                    if (direction == HORIZONTAL)
                    {
                        h += SSPACE;
                    }
                    else
                    {
                        w += SSPACE;
                    }

                    if (getRoot() != cur)
                    {
                        if (direction == HORIZONTAL)
                        {
                            cpanel.add(new OrgLine(NONE, backGround),
                                BorderLayout.NORTH);
                            h += SSPACE;
                        }
                        else
                        {
                            cpanel.add(new OrgLine(NONE, backGround),
                                BorderLayout.WEST);
                            w += SSPACE;
                        }
                    }

                    if (getNbChildExpanded(cur) > 0)
                    {
                        if (direction == HORIZONTAL)
                        {
                            cpanel.add(new OrgLine(NONE, backGround),
                                BorderLayout.SOUTH);
                        }
                        else
                        {
                            cpanel.add(new OrgLine(NONE, backGround),
                                BorderLayout.EAST);
                        }
                    }
                    else
                    {
                        if (direction == HORIZONTAL)
                        {
                            cpanel.add(Box.createVerticalStrut(SSPACE),
                                BorderLayout.SOUTH);
                        }
                        else
                        {
                            cpanel.add(Box.createHorizontalStrut(SSPACE),
                                BorderLayout.EAST);
                        }
                    }

                    JPanel dpanel = createPP(cur);
                    w += (int) dpanel.getPreferredSize().getWidth();
                    h += (int) dpanel.getPreferredSize().getHeight();

                    if (direction == HORIZONTAL)
                    {
                        w += SPACEV;
                    }
                    else
                    {
                        h += SPACEV;
                    }

                    cpanel.add(dpanel, BorderLayout.CENTER);

                    if (direction == HORIZONTAL)
                    {
                        cpanel.add(Box.createHorizontalStrut(SPACEV),
                            BorderLayout.WEST);
                    }
                    else
                    {
                        cpanel.add(Box.createVerticalStrut(SPACEV),
                            BorderLayout.NORTH);
                    }

                    cpanel.setPreferredSize(new Dimension(w, h));
                    cpanel.setMaximumSize(new Dimension(w, h));
                    cpanel.setBackground(backGround);

                    //cpanel.setBorder (new javax.swing.border.LineBorder(Color.red));
                    panel.add(cpanel);

                    if (first)
                    {
                        if (direction == HORIZONTAL)
                        {
                            panel.setMaximumSize(new Dimension(
                                    Integer.MAX_VALUE,
                                    (int) cpanel.getMaximumSize().getHeight()));
                        }
                        else
                        {
                            panel.setMaximumSize(new Dimension(
                                    (int) cpanel.getMaximumSize().getWidth(),
                                    Integer.MAX_VALUE));
                        }

                        first = false;
                    }

                    prevx = x;
                }
            }

            if (direction == HORIZONTAL)
            {
                panel.add(Box.createHorizontalGlue());
            }
            else
            {
                panel.add(Box.createVerticalGlue());
            }

            panel.setBackground(backGround);
            add(panel);
        }
    }

    /**
     * Generates an orgchart in Sema mode.
     */
    private void processSema()
    {
        XJPanel3 pan = new XJPanel3();
        pan.setH(getMaxHeight(new Integer(1)));

        pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS));
        pan.setBackground(backGround);

        JPanel vert1 = createPP(getRoot());
        pan.add(vert1);
        pan.add(new OrgLine1(backGround));

        int nbChild = getNbChildExpanded(getRoot());

        int nbFLignes = nbChild / nbCols;
        int nbReste = nbChild % nbCols;
        pan.setReste(nbReste);

        for (int i = 0; i < nbFLignes; i++)
        {
            XJPanel xpan = new XJPanel();
            xpan.setLayout(new BoxLayout(xpan, BoxLayout.X_AXIS));
            xpan.setBackground(backGround);
            xpan.add(Box.createHorizontalStrut(SPACEV));

            for (int j = 0; j < nbCols; j++)
            {
                JPanel pi = new JPanel();
                pi.setLayout(new BoxLayout(pi, BoxLayout.Y_AXIS));
                pi.setBackground(backGround);

                JPanel verti = createPP((DefaultMutableTreeNode) getRoot()
                                                                     .getChildAt((i * nbCols) +
                            j));
                pi.add(new OrgLine1(backGround));
                pi.add(verti);
                xpan.add(pi);
                xpan.add(Box.createHorizontalStrut(SPACEV));

                if (j == 0)
                {
                    xpan.setV1(verti);
                    xpan.setP1(pi);
                }
                else if (j == (nbCols - 1))
                {
                    xpan.setV2(verti);
                    xpan.setP2(pi);
                }
            }

            pan.add(xpan);
            horizList.add(xpan);
            pan.add(Box.createVerticalStrut(SPACEV));
        }

        if (nbReste > 0)
        {
            XJPanel xpan = new XJPanel();
            xpan.setLayout(new BoxLayout(xpan, BoxLayout.X_AXIS));
            xpan.setBackground(backGround);
            xpan.add(Box.createHorizontalStrut(SPACEV));

            for (int i = 0; i < nbReste; i++)
            {
                JPanel pi = new JPanel();
                pi.setLayout(new BoxLayout(pi, BoxLayout.Y_AXIS));
                pi.setBackground(backGround);

                JPanel verti = createPP((DefaultMutableTreeNode) getRoot()
                                                                     .getChildAt((nbFLignes * nbCols) +
                            i));
                pi.add(new OrgLine1(backGround));
                pi.add(verti);
                xpan.add(pi);
                xpan.add(Box.createHorizontalStrut(SPACEV));

                if (i == 0)
                {
                    xpan.setV1(verti);
                    xpan.setP1(pi);
                }

                if (i == (nbReste - 1))
                {
                    xpan.setV2(verti);
                    xpan.setP2(pi);
                }
            }

            pan.add(xpan);
            horizList.add(xpan);
        }

        add(pan);
    }

    /**
     * Generates org chart.
     */
    public final void doIt()
    {
        _logger.debug("doIt");
        horizList = new ArrayList();
        computeMaxWidth(getRoot());

        int rnlen = ((String) ((Hashtable) getRoot().getUserObject()).get(NAME)).length();
        int rlen = MINW + ((rnlen + 2) * W_FACTOR);

        /*
             if ((rlen > getMaxWidth()) && ((schema == null) || (schema.getOrgchartCellWidth() == 0)))
             {
                setMaxWidth(rlen);
             }
        */
        if (direction == TREE)
        {
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            add(treeCreateVert(getRoot(), true, NONE, null, null));

            if (getNbChildExpanded(getRoot()) > 0)
            {
                treeProcessChildren(getRoot());
            }

            //DW/2573/BeginPatch
        }
        else if (direction == SEMALIKE)
        {
            int nbChild = getNbChildExpanded(getRoot());

            if (nbChild == 0)
            {
                add(createPP(getRoot()));
            }
            else
            {
                processSema();
            }

            //DW/2573/EndPatch
        }
        else
        {
            if (mode == COMPRESSED)
            {
                doComputeCondenseCoords();
                doDessineCondense();
            }
            else
            {
                JPanel vert1 = null;

                int nbChild = getNbChildExpanded(getRoot());

                if (nbChild == 0)
                {
                    vert1 = createVert(getRoot(), false, NONE, null, null);
                }
                else
                {
                    vert1 = createVert(getRoot(), true, NONE, null, null);

                    JPanel horiz1 = processChildren(getRoot());
                    vert1.add(horiz1);
                }

                add(vert1);

                recalcule();
            }
        }

        invalidate();
        repaint();
        validate();
    }

    /**
     * Draws the orgchart.
     *
     * @param g  Graphics on which to draw.
     */
    @Override
	public final void paint(final Graphics g)
    {
        _logger.debug("paint");
        recalcule();
        super.paint(g);
        doCompute(this);

        //DW/2587/BeginPatch

        /*
                Enumeration enum4 = getRoot().depthFirstEnumeration();

                while (enum4.hasMoreElements()) {
                    DefaultMutableTreeNode curnode =
                        (DefaultMutableTreeNode) enum4.nextElement();

                    Hashtable info = (Hashtable) curnode.getUserObject();
                    int x = ((Integer) info.get(XCOORD)).intValue();
                    int y = ((Integer) info.get(YCOORD)).intValue();
                    int w = ((Integer) info.get(WIDTH)).intValue();
                    int h = ((Integer) info.get(HEIGHT)).intValue();

                    g.drawLine(x + w, y + 4, x + w, y + h + 3);
                    g.drawLine(x + w + 1, y + 4, x + w + 1, y + h + 3);
                    g.drawLine(x + w + 2, y + 4, x + w + 2, y + h + 3);
                    g.drawLine(x + w + 3, y + 4, x + w + 3, y + h + 3);
                    g.drawLine(x + 4, y + h, x + w + 3, y + h);
                    g.drawLine(x + 4, y + h + 1, x + w + 3, y + h + 1);
                    g.drawLine(x + 4, y + h + 2, x + w + 3, y + h + 2);
                    g.drawLine(x + 4, y + h + 3, x + w + 3, y + h + 3);
                }
        */

        //DW/2587/EndPatch
    }

    /**
     * Computes cells coordinates.
     *
     * @param c  Top container.
     */
    private void doCompute(final Container c)
    {
        doCompute(c, null);
    }

    /**
     * Computes cells coordinates ans stores them.
     *
     * @param c  Top container.
     * @param l  List where to store coordinates.
     */
    private void doCompute(final Container c, final List l)
    {
        _logger.debug("doCompute");

        Component[] compo = c.getComponents();

        for (int n = 0; n < compo.length; n++)
        {
            if (compo[n] instanceof XJButton)
            {
                Container cur = (Container) compo[n];
                Hashtable info = (Hashtable) (((XJButton) cur).getNode()).getUserObject();
                int w = (int) cur.getBounds().getWidth();
                int h = (int) cur.getBounds().getHeight();
                info.put(WIDTH, new Integer(w));
                info.put(HEIGHT, new Integer(h));

                int cX = 0;
                int cY = 0;

                do
                {
                    cX += cur.getBounds().getX();
                    cY += cur.getBounds().getY();
                    cur = cur.getParent();
                }
                while (cur.getClass().toString().indexOf("OrgChartPanel") == -1);

                info.put(XCOORD, new Integer(cX));
                info.put(YCOORD, new Integer(cY));

                //DW/2572/BeginPatch
                if (l != null)
                {
                    Hashtable resinfo = new Hashtable();
                    resinfo.put(NAME, info.get(NAME));
                    resinfo.put(DN, info.get(DN));
                    resinfo.put(XCOORD, new Integer(cX));
                    resinfo.put(YCOORD, new Integer(cY));
                    resinfo.put(WIDTH, new Integer(w));
                    resinfo.put(HEIGHT, new Integer(h));
                    l.add(resinfo);
                }

                //DW/2572/EndPatch
                if ((cX + w) > maxX)
                {
                    maxX = cX + w;
                }

                if ((cY + h) > maxY)
                {
                    maxY = cY + h;
                }

                Integer alevel = (Integer) info.get(LEVEL);

                if ((crits != null) && (levelAttribs != null) &&
                        (alevel.intValue() > crits.length))
                {
                    alevel = new Integer(levelAttribs.size() - 1);
                }

                List alist = null;

                if (levelAttribs != null)
                {
                    alist = (List) levelAttribs.get(alevel);
                }

                if (alist != null)
                {
                    info.put(ATTRIBS, alist);
                }
            }

            if (compo[n] instanceof Container)
            {
                //DW/2572/BeginPatch
                //doCompute((Container) compo[n]);
                doCompute((Container) compo[n], l);

                //DW/2572/EndPatch
            }
        }
    }

    /**
     * Generates PDF orgchart on file.
     *
     * @param filename  PDF file name.
     */
    public void doPrint(final String filename)
    {
        _logger.debug("doPrint");

        Container cur = baseCell;

        do
        {
            cur = cur.getParent();
        }
        while (cur.getClass().toString().indexOf("OrgChartPanel") == -1);

        maxX = 0;
        maxY = 0;
        doCompute(cur);

        if ((maxX > MAX_PDF) || (maxY > MAX_PDF))
        {
            throw new RuntimeException(
                "Organigramme trop large pour g�n�ration PDF");
        }

        //DW/2551
        //        PrintOrga.doPrintOrga(filename, baseCell.getNode(), attribs, 297, 210);
        PrintOrga.doPrintOrga(filename, baseCell.getNode(), attribs, 0, 0);

        //DW/2551
    }

    /**
     * Generates PDF orgchart on stream.
     *
     * @return The PDF stream.
     */
    public ByteArrayOutputStream doPrint()
    {
        _logger.debug("doPrint");

        Container cur = baseCell;

        do
        {
            cur = cur.getParent();
        }
        while (cur.getClass().toString().indexOf("OrgChartPanel") == -1);

        maxX = 0;
        maxY = 0;
        doCompute(cur);

        if ((maxX > MAX_PDF) || (maxY > MAX_PDF))
        {
            throw new RuntimeException(
                "Organigramme trop large pour g�n�ration PDF");
        }
       /* 
        try{
        	File f = new File( "C:\\outForPdf.jpg" );
        	f.createNewFile();
        	FileOutputStream out = new FileOutputStream(f);
        	out.write(PrintOrga.doPrintOrga(baseCell.getNode(), attribs, 0, 0).toByteArray());
        	out.close();
        }catch(Exception e){}*/

        //DW/2551
        //        return PrintOrga.doPrintOrga( baseCell.getNode(), attribs, 297, 210);
        return PrintOrga.doPrintOrga(baseCell.getNode(), attribs, 0, 0);

        //DW/2551
    }

    //DW/2572/BeginPatch

    /**
     * Generates orgchart as a GIF file.
     *
     * @return list containing as first element the image
     *         (java.io.ByteArrayOutputStream) and as second element
     *         a java.util.Hashtable containing elements corresponding to cells
     *         with as properties : the name (OrgChartpanel.NAME), the dn
     *         (OrgChartPanel.DN), and the coordinates (OrgChartPanel.XCOORD,
     *         OrgChartPanel.YCOORD, OrgChartPanel.WIDTH and
     *         OrgChartPanel.HEIGHT).
     */
    public List doPrintAsGif()
    {
        _logger.debug("doPrintAsGif");

        Container cur = baseCell;
        List lresult = new ArrayList();
        List infos = new ArrayList();

        do
        {
            cur = cur.getParent();
        }
        while (cur.getClass().toString().indexOf("OrgChartPanel") == -1);

        Container togif = cur;

        maxX = 0;
        maxY = 0;
        doCompute(cur, infos);

        try
        {
            BufferedImage img = new BufferedImage(maxX, maxY,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = img.createGraphics();
            // //AMVOU/BeginPatch
            // .. set attributes ..
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         
            // .. clear canvas ..
            graphics.clearRect(0, 0, getSize().width, getSize().height);
          //AMVOU/EndPatch
            togif.paint(graphics);

            ByteArrayOutputStream result = new ByteArrayOutputStream();

            //DW/2597/BeginPatch
            int[][] pixels = TestQuantize.getPixels(img);
            int[] palette = Quantize.quantizeImage(pixels, MAX_GIF);
            ImageFrame reduced = new ImageFrame();
            reduced.setImage(palette, pixels);

            Image gifimg = reduced.getImage();
            new GifEncoder(gifimg, result).encode();

            /*
                      new GifEncoder(img, result).encode();
            */
            //DW/2597/EndPatch
            lresult.add(result);
//DW/2641/BeginPatch
            reduced.dispose();
//DW/2641/EndPatch
        }
        catch (java.io.IOException ioe)
        {
            // GifEncoder throws IOException when GIF contains too many colors
            // if this happens, filter image to reduce number of colors
            _logger.error(ioe.getMessage());
        }

        lresult.add(infos);

        return lresult;
    }

    /**
     * Generates orgchart as a Java 1.4 compliant image format file.
     * Examples : JPG ou PNG.
     *
     * @param imagetype  Type of image (JPG or PNG).
     * @return list containing as first element the image
     *         (java.io.ByteArrayOutputStream) and as second element
     *         a java.util.Hashtable containing elements corresponding to cells
     *         with as properties : the name (OrgChartpanel.NAME), the dn
     *         (OrgChartPanel.DN), and the coordinates (OrgChartPanel.XCOORD,
     *         OrgChartPanel.YCOORD, orgChartPanel.WIDTH and
     *         OrgChartPanel.HEIGHT).
     */
    public List doPrintAsJpgOrPng(final String imagetype)
    {
        _logger.debug("doPrintAsJpgOrPng " + imagetype);

        Container cur = baseCell;
        List lresult = new ArrayList();
        List infos = new ArrayList();

        do
        {
            cur = cur.getParent();
        }
        while (cur.getClass().toString().indexOf("OrgChartPanel") == -1);

        Container tojpg = cur;

        maxX = 0;
        maxY = 0;
        doCompute(cur, infos);

        try
        {
            BufferedImage img = new BufferedImage(maxX, maxY,BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics = img.createGraphics(); 
            //AMVOU/BeginPatch 29/08/2012
            img = getImageFromPdf(PrintOrga.doPrintOrga(baseCell.getNode(), attribs, 0, 0).toByteArray());
            //tojpg.paint(graphics);
            ByteArrayOutputStream result = new ByteArrayOutputStream();
            ImageIO.write(img, imagetype.toLowerCase(), result);
            
            /*ByteArrayOutputStream buf = PrintOrga.doPrintOrga(baseCell.getNode(), attribs, 0, 0);
            InputStream in = new ByteArrayInputStream(buf.toByteArray());
            ImageIO.write(bImageFromConvert, imagetype.toLowerCase(), result);
			BufferedImage bImageFromConvert = ImageIO.read(in);
			*/	
         

            lresult.add(result);
            
           /* File f = new File( "C:\\outForJpg.jpg" );
        	f.createNewFile();
        	FileOutputStream out = new FileOutputStream(f);
        	out.write(result.toByteArray());
        	out.close();*/
        	 //AMVOU/EndPatch
        }
        catch (java.io.IOException ioe)
        {
            _logger.error(ioe.getMessage());
        }

        lresult.add(infos);

       return lresult;
    }

    /**
     * Sets number of columns in Sema mode.
     *
     * @param nb  Number of columns.
     */
    public final void setNbCols(final int nb)
    {
        nbCols = nb;
    }

    //DW/2573/EndPatch

    /**
     * Gets current orgchart instance.
     *
     * @return The instance.
     */
    public OrgChartPanel getInstance()
    {
        return orgchart;
    }

//DW/2673/BeginPatch
    /**
     * Sets the orgchart background color.
     *
     * @param value  Color.
     */
    public void setBackGround(Color value)
    {
        this.backGround = value;
        setBackground(this.backGround);
    }
//DW/2673/EndPatch
    
//DW/2600/BeginPatch
    /**
     * Sets the cell background color.
     *
     * @param value  Color.
     */
    public void setCellColor(Color value)
    {
        this.cellColor = value;
    }
//DW/2600/EndPatch

//DW/2615/BeginPatch
    /**
     * Sets default photo file name.
     *
     * @param value  File name.
     */
    public void setDefaultPhoto(String value)
    {
        defaultPhoto = value;
        PrintOrga.setDefaultPhoto(value);
    }
    
  //AMVOU/BeginPatch
    private BufferedImage getImageFromPdf(byte[] bytes)
    {
    	/**instance of PdfDecoder to convert PDF into image*/
    	PdfDecoder decode_pdf = new PdfDecoder(true);

    	/**set mappings for non-embedded fonts to use*/
    	FontMappings.setFontReplacements();
    	
    	BufferedImage img = null;

    	/**open the PDF file - can also be a URL or a byte array*/
    	try {    	    	
    			decode_pdf.openPdfArray(bytes); //bytes is byte[] array with PDF
    	    	/**get all the pages as an image*/
    	    	img=decode_pdf.getPageAsImage(decode_pdf.getPageCount());
    		
    		/**close the pdf file*/
    		decode_pdf.closePdfFile();
    	}
    	catch (org.jpedal.exception.PdfException e2)
    	{
    		e2.printStackTrace();
    	}
    	return img;
    }
  //AMVOU/EndPatch
//DW/2615/EndPatch
}
